package com.wind.cloud.common.lock.annotation;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.wind.cloud.common.lock.ILock;
import com.wind.cloud.common.util.SpringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;

/**
 * 锁aop处理(保证在事务外层)
 *
 * @author wind.
 */
@Aspect
@Order(1)
public class LockAspect {

    private static final Logger logger = LoggerFactory.getLogger(LockAspect.class);

    private static volatile ILock lock;

    @Pointcut("@annotation(com.wind.cloud.common.lock.annotation.Lock)")
    private void pointcut() {
        // do nothing
    }

    @Around("pointcut()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        Lock lock = lock(pjp);
        String value = IdWorker.getIdStr();
        boolean isLock = lock.timeoutMills() > 0 ?
                getLock().lock(lock.value(), value, lock.expireMills(), lock.timeoutMills()) : getLock().tryLock(lock.value(), value, lock.expireMills());
        if (isLock) {
            try {
                pjp.proceed();
            } finally {
                getLock().unLock(lock.value(), value);
            }
        } else {
            logger.info("{}没有获得锁", lock.value());
        }
    }

    private Lock lock(ProceedingJoinPoint pjp) {
        MethodSignature methodName = (MethodSignature) pjp.getSignature();
        Method method = methodName.getMethod();
        return method.getAnnotation(Lock.class);
    }

    private static ILock getLock() {
        if (lock == null) {
            synchronized (ILock.class) {
                if (lock == null) {
                    lock = SpringUtils.getBean(ILock.class);
                }
            }
        }
        return lock;
    }

}

